extends Node
class_name AbilitySystemComponent

@export var active:bool = true

## 组件的所有者
@export var owner_actor:Node
## 属性列表
@export var attribute_set:AttributeSet
## 默认的Ability
@export var abilities:Array[Ability]
var cooldowns:Dictionary = {}
## 标签列表
@export var tags:Array[String]

var modifier_result_table:Dictionary = {}

# 技能生命周期枚举
enum LifeCycle {
	Activated,
	Blocked,
	Cancelled,
	Ended,
	CooldownStarted,
	CooldownEnded
}

func _ready() -> void:
	if owner_actor == null:
		return
	init_all_abilities()
	modifier_result_table = form_modifier_result_table(attribute_set)


func init_all_abilities():
	for ability in abilities:
		init_ability(ability)

func init_ability(ability:Ability) -> bool:
	# 生命周期行为
	if not ability.activated.is_connected(_on_ability_activated):
		ability.activated.connect(_on_ability_activated)
	# 冷却
	if ability.cooldown_grow_curve:
		create_cooldown(ability)
		
	# 技能为 actor 附加的 tag
	return true

# 冷却时间根据技能等级由曲线中取值，是否在技能结束阶段即时生成timer更好？
func create_cooldown(ability:Ability):
	if not cooldowns.has(ability):
		var timer = Timer.new()
		timer.one_shot = true
		cooldowns[ability] = timer
		timer.stop()
		timer.timeout.connect(func():
			# 技能周期切换至冷却结束周期
			prints(ability.ability_name,"is ready!")
			)
		add_child(timer)

# 技能激活时的固定行为
func _on_ability_activated(ability:Ability):
	# 是否有资格激活（不允许其他ASC直接激活ability）
	
	# 添加/删除对应周期的tags
	handle_lifecycle_tagging(LifeCycle.Activated,ability)
	# 有冷却则添加冷却
	if cooldowns.has(ability):
		var timer = cooldowns.get(ability) as Timer
		if timer.is_stopped():
			timer.wait_time = ability.cooldown
			timer.start()
			


# 应用技能的cost
func apply_cost(costs:Effect) -> bool: # 资源消耗本质也是 Effect
	# 无需资源消耗
	if costs == null:
		return true
	if costs.modifiers.size() == 0:
		return true
		
	for modifier in costs.modifiers:
		var attribute = attribute_set.get_attribute_by_name(modifier.attribute_to_modify)
		if attribute:
			if attribute.base_value + modifier.value < 0:
				return false
	apply_effect(costs)
	return true


# 应用一组effect
func apply_effects(effects:Array[Effect]) -> bool:
	for effect in effects:
		if not apply_effect(effect):
			return false
	return true


# 应用单个Effect
func apply_effect(effect:Effect) -> bool:
	match effect.duration_type:
		## 将一个 Effect 的 modifiers 计算结果加入聚合表对其分类统计
		Effect.DurationType.Instant:
			# 对于立即应用的Effect，创建临时聚合表
			var temp_modifier_result_table:Dictionary = form_modifier_result_table(attribute_set)
			# 把 Effect 中的每一个 modifier 值分别加入对应表格中
			extract_result_to_table(effect.modifiers,temp_modifier_result_table)
			
			# 根据表格数据分别处理各个属性的修改
			set_attribute_by_table(temp_modifier_result_table,Attribute.ValueType.BaseValue)
			
		Effect.DurationType.Duration:
			# 临时聚合表记录此 duration 类型 effect 添加的 Modifier 计算值
			# 临时表用于Duration计时结束后擦除常驻聚合表中的数据
			var record_modifier_result_table = form_modifier_result_table(attribute_set)
			extract_result_to_table(effect.modifiers,record_modifier_result_table)
			# 将 modifier 计算值保存在常驻聚合表中
			extract_result_to_table(effect.modifiers,modifier_result_table)
			# 设置定时器，timeout时将被记录的数据“撤回”,即从对应数组中erase该条数据
			var timer = Timer.new()
			timer.wait_time = effect.time_out
			timer.one_shot = true
			timer.autostart = true
			timer.timeout.connect(func():
				erase_aggregated_table_data(record_modifier_result_table,modifier_result_table)
				timer.queue_free()
			)
			add_child(timer)
		
		Effect.DurationType.Infinite:
			extract_result_to_table(effect.modifiers,modifier_result_table)
		
		
	return true

#region ASC杂项
# 激活一个ability
func activate_one(ability:Ability):
	# ASC 未激活时，不激活 ability
	if not active:
		return
	
	if abilities.has(ability):
		ability.executor = self
		
		if internal_can_activate_ability(ability):
			ability.activate()

# ASC内部检查Ability是否可执行
func internal_can_activate_ability(ability:Ability) -> bool:
	# 冷却检查
	if cooldowns.has(ability):
		var timer = cooldowns[ability] as Timer
		if not timer.is_stopped():
			return false
	# blocked tags 检查
	if TagSystem.any_tags_match(ability.tags_block,tags):
		return false
	# required tags 检查
	if not TagSystem.all_tags_match(ability.tags_activation_required,tags):
		return false
	# cost 资源消耗检查
	return ability.can_be_activate


# 验证ability是否可被学习，是则加入列表
func grant_ability(ability:Ability):
	if TagSystem.all_tags_match(ability.tags_learn_required,tags):
		abilities.append(ability)


# 在可用的Ability列表里面寻找,存在该ability则返回，不存在则返回null
func find_by(predicate:Callable) -> Ability:
	for ability in abilities:
		if predicate.call(ability):
			return ability
	return null


# 技能周期
## @experimental: 该方法尚未完善。
func handle_lifecycle_tagging(lifecycle:LifeCycle,ability:Ability):
	match lifecycle:
		LifeCycle.Activated:
			add_tags(ability.tags_activation)
			remove_tags(ability.tags_to_remove_on_activation)
			return


# 为ASC添加Tags
func add_tags(tags_to_add:Array[String]):
	for tag in tags_to_add:
		tags.append(tag)


# 为ASC移除Tags
func remove_tags(tags_to_del:Array[String]):
	for tag in tags_to_del:
		tags.erase(tag)


# 获取一个经聚合计算后的current_value (并非Attribute中的current_value)
func get_attribute_value(name:String) -> float:
	var base_value:float = attribute_set.get_attribute_by_name(name).base_value
	var current_value:float
	
	current_value = aggregated_calculation(base_value,modifier_result_table[name])
	
	return current_value

# 聚合计算，aggregate_item是聚合表中属性的键对应的值，是一个包含 add，multipl 的 Dictionary
func aggregated_calculation(base_value:float,aggregate_item:Dictionary) -> float:
	var aggregated_value:float = 0.0
	
	# 计算 Additive
	var Additive:float = 0.0
	for a in aggregate_item.ADD:
		Additive += a
	# 计算 Multiplicitive
	var Multiplicitive:float = 0.0
	for m in aggregate_item.MULTIPLY:
		Multiplicitive += m
	
	aggregated_value = (base_value + Additive) * (1 + Multiplicitive)
	# 存在 OVERRIDE 则直接覆盖
	if aggregate_item.OVERRIDE:
		aggregated_value = aggregate_item.OVERRIDE.back()
		
	return aggregated_value

#endregion


#region modifier 相关方法

# 擦除聚合表中的数据
func erase_aggregated_table_data(erase_table:Dictionary,source_table:Dictionary):
	for erase_item in erase_table.values():
		#prints(erase_item,source_table[erase_item.attribute_name])
		
		for value in erase_item.ADD:
			source_table[erase_item.attribute_name].ADD.erase(value)
		for value in erase_item.MULTIPLY:
			source_table[erase_item.attribute_name].MULTIPLY.erase(value)
		for value in erase_item.OVERRIDE:
			source_table[erase_item.attribute_name].OVERRIDE.erase(value)
	


# 使用聚合表设置 base_value 或者 curtent_value 
func set_attribute_by_table(table:Dictionary,value_type:Attribute.ValueType):
	for modify_data in table.values():
		if modify_data.ADD == [] and modify_data.MULTIPLY == [] and modify_data.OVERRIDE == []:
			continue
		else:
			var base_value = attribute_set.get_attribute_by_name(modify_data.attribute_name).base_value
			var aggregated_value = aggregated_calculation(base_value,modify_data)
			
			if value_type == Attribute.ValueType.BaseValue:
				attribute_set.set_attribute_base_value(modify_data.attribute_name, aggregated_value)
			if value_type == Attribute.ValueType.CurrentValue:
				attribute_set.set_attribute_current_value(modify_data.attribute_name,aggregated_value)

# 将 modifier 的数据提取到表格中
func extract_result_to_table(modifiers:Array[Modifier],table:Dictionary):
	for modifier in modifiers:
		var base_value = attribute_set.get_attribute_by_name(modifier.attribute_to_modify).base_value
		var calculated_value = calculate_modifier(base_value,modifier)
		match modifier.modifier_option:
			Modifier.ModifierOp.ADD:
				table[modifier.attribute_to_modify].ADD.append(calculated_value)
			Modifier.ModifierOp.MULTIPLY:
				table[modifier.attribute_to_modify].MULTIPLY.append(calculated_value)
			Modifier.ModifierOp.OVERRIDE:
				table[modifier.attribute_to_modify].OVERRIDE.append(calculated_value)


# 根据modifier的配置计算,参数base_value与Attribute的base_value意义不同
func calculate_modifier(base_value:float,modifier:Modifier) -> float:
	var calculated_value:float = 0
	
	match modifier.magnitude_calculation:
		Modifier.MagnitudeCalculation.SCALABLEFLOAT:
			calculated_value = modifier.value
		Modifier.MagnitudeCalculation.ATTRIBUTEBASED:
			calculated_value = base_value * modifier.value
		Modifier.MagnitudeCalculation.SETBYCALLER:
			printerr("SET BY CALLER 类型的 Modifier 尚待开发")
			calculated_value = base_value
	
	return calculated_value

## 构造空 modifier 聚合表
func form_modifier_result_table(a_s:AttributeSet) -> Dictionary:
	var table:Dictionary = {}
	for attribute in a_s.attributes:
		table[attribute.attribute_name] = {
			"attribute_name":attribute.attribute_name,
			"ADD":[],"MULTIPLY":[],"OVERRIDE":[]
			}
	return table
	
#endregion
